/*
 * Copyright 2006-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.martinimix.domain.payment;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.GregorianCalendar;


/**
 * Provides a credit card payment bean.
 * 
 * @author Scott Rossillo
 *
 */
public class CreditCard implements PaymentMethod, Serializable, Cloneable {

	private static final long serialVersionUID = 1L;
	
	/**
	 * The the payment method type for credit cards.
	 */
	public final static String PAYMENT_TYPE_CREDIT_CARD = "CCD";
	
	public final static String STATUS_ENABLED = "ENB";
	public final static String STATUS_DISABLED = "DSB";
	
	/**
	 * @@BusinessObjectProperty("ccd_id")
	 */
	private Long id;
	
	/**
	 * @@BusinessObjectProperty("cardNum")
	 */
	private String cardNumber;
	
	/**
	 * @@BusinessObjectProperty("cardVerifyNum")
	 */
	private String cardSecurityCode;
	
	/**
	 * @@BusinessObjectProperty("currency_cd")
	 */
	private String currencyCode;
	
	/**
	 * @@BusinessObjectProperty("status_cd")
	 */
	private String statusCode;
	
	/**
	 * @@BusinessObjectProperty("cardBrand_cd")
	 */
	private String brand;
	
	private String cardholderName;
	
	/**
	 * @@BusinessObjectProperty("ccd_usa_id")
	 */
	private Long customerId;
	
	/** 
	 * @@BusinessObjectProperty("BillingAddressID", attribute=true)
	 */
	private Long billingAddressId;
	
	private Long createdBy;
	private Long modifiedBy;
	
	private BigDecimal amount;
	
	/**
	 * @@BusinessObjectProperty("cardMonth_cd")
	 */
	private int expirationMonth;
	
	/**
	 * @@BusinessObjectProperty("cardYear_cd")
	 */
	private int expirationYear;
	
	/**
	 * @@BusinessObjectProperty("cardExpiration")
	 */
	private Calendar expirationDate;
	
	private boolean defaultCreditCard; 
	
	/**
	 * Creates a new credit card.
	 */
	public CreditCard() {
		
		amount = BigDecimal.valueOf(0, 2);
		defaultCreditCard = false;
	}
	
	/**
	 * Creates a copy of the given credit card.
	 *  
	 * @param creditCard the <code>CreditCard</code> to copy
	 */
	protected CreditCard(CreditCard creditCard) {
		
		this.id = creditCard.id;
		this.amount = creditCard.amount;
		this.billingAddressId = creditCard.billingAddressId;
		this.brand = creditCard.brand;
		this.cardholderName = creditCard.cardholderName;
		this.cardNumber = creditCard.cardNumber;
		this.cardSecurityCode = creditCard.cardSecurityCode;
		this.createdBy = creditCard.createdBy;
		this.currencyCode = creditCard.currencyCode;
		this.customerId = creditCard.customerId;
		this.defaultCreditCard = creditCard.defaultCreditCard;
		this.expirationDate = creditCard.expirationDate;
		this.expirationMonth = creditCard.expirationMonth;
		this.expirationYear = creditCard.expirationYear;
		this.modifiedBy = creditCard.modifiedBy;
		this.statusCode = creditCard.statusCode;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public boolean isDefaultCreditCard() {
		return defaultCreditCard;
	}

	public void setDefaultCreditCard(boolean defaultCreditCard) {
		this.defaultCreditCard = defaultCreditCard;
	}

	public String getCardNumber() {
		return cardNumber;
	}
	
	public void setCardNumber(String cardNumber) {
		this.cardNumber = cardNumber;
		setBrand(CreditCardToolkit.getBrand(cardNumber));
	}
	
	public String getCardSecurityCode() {
		return cardSecurityCode;
	}
	
	public void setCardSecurityCode(String cardSecurityCode) {
		this.cardSecurityCode = cardSecurityCode;
	}
	
	public String getCurrencyCode() {
		return currencyCode;
	}

	public void setCurrencyCode(String currencyCode) {
		this.currencyCode = currencyCode;
	}

	public String getStatusCode() {
		return statusCode;
	}

	/* (non-Javadoc)
	 * @see net.martinimix.domain.payment.PaymentMethod#getPaymentMethodTypeCode()
	 */
	public String getPaymentMethodTypeCode() {
		return PAYMENT_TYPE_CREDIT_CARD;
	}

	public void setStatusCode(String statusCode) {
		this.statusCode = statusCode;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getCardholderName() {
		return cardholderName;
	}

	public void setCardholderName(String cardholderName) {
		this.cardholderName = cardholderName;
	}

	public Long getCustomerId() {
		return customerId;
	}

	public void setCustomerId(Long customerId) {
		this.customerId = customerId;
	}

	public Long getBillingAddressId() {
		return billingAddressId;
	}

	public void setBillingAddressId(Long billingAddressId) {
		this.billingAddressId = billingAddressId;
	}

	public Long getCreatedBy() {
		return createdBy;
	}

	public void setCreatedBy(Long createdBy) {
		this.createdBy = createdBy;
	}

	public Long getModifiedBy() {
		return modifiedBy;
	}

	public void setModifiedBy(Long modifiedBy) {
		this.modifiedBy = modifiedBy;
	}

	/**
	 * Returns the charge amount for this credit card.
	 * 
	 * @return a <code>BigDecimal</code> containing the
	 * amount of the charge on this credit card
	 */
	public BigDecimal getAmount() {
		return amount;
	}

	/**
	 * Sets the charge amount for this credit card.
	 * 
	 * @param amount the amount to charge on this credit card
	 */
	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}

	/**
	 * Returns the expiration month for this credit card.
	 * 
	 * @return the expiration month for this card
	 */
	public int getExpirationMonth() {
		return expirationMonth;
	}
	
	/**
	 * Sets the expiration month for this credit card.
	 * 
	 * @param expirationMonth the month this card expires
	 */
	public void setExpirationMonth(int expirationMonth) {
		
		this.expirationMonth = expirationMonth;
		updateExpirationDate();
	}
	
	/**
	 * Returns the expiration year for this card.
	 * 
	 * @return the expiration year for this card.
	 */
	public int getExpirationYear() {
		return expirationYear;
	}
	
	public void setExpirationYear(int expirationYear) {
		
		this.expirationYear = expirationYear;
		updateExpirationDate();
	}
	
	/**
	 * Returns the expiration date for this credit card
	 * 
	 * @return the expiration date for this card as a
	 * <code>Calendar</code>
	 */
	public Calendar getExpirationDate() {
		
		return expirationDate;
	}
	
	/**
	 * Sets the expiration date for this credit card
	 * 
	 * @param expirationDate a <code>Calendar</code> containing the exiration
	 * month and year to set on this <code>CreditCard</code>
	 */
	public void setExpirationDate(Calendar expirationDate) {
		
		this.expirationDate = expirationDate;
		this.expirationMonth = expirationDate.get(Calendar.MONTH) + 1;
		this.expirationYear = expirationDate.get(Calendar.YEAR);
	}
	
	/**
	 * Updates the credit card's expiration date from its expiration
	 * month and year properties.
	 */
	private void updateExpirationDate() {
		
		int expMonth = expirationMonth;
		// if customer did not select a month in the dropdown
		if(expMonth < 1){
			expMonth = 1;
		}
		
		Calendar dt = new GregorianCalendar(expirationYear, expMonth - 1, 1);
		dt.set(Calendar.DAY_OF_MONTH, dt.getActualMaximum(Calendar.DAY_OF_MONTH));
		this.expirationDate = dt;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
	
		final StringBuffer buf = new StringBuffer(256);
		
		buf.append("CreditCard[");
		buf.append("id=").append(this.getId());
		buf.append(", usa_id=").append(this.getCustomerId());
		buf.append(']');
		
		return buf.toString();
	}
	
}
